home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
System Booster
/
System Booster.iso
/
SYS
/
s
/
GHBackup.mrbk
< prev
next >
Wrap
Text File
|
1996-09-26
|
19KB
|
574 lines
/*********************************************************************
GHBackup.rexx Version 1.1 - Glenn Holliday's Automated Backup
AREXX program to run MRBackup for incremental backups.
Calling template:
rx GHBackup [homePath [backupPath [lastFullBackupDate]]]
Description:
This program can easily be adapted to your own set of backup
rules. You _do_ want to examine the code and tweak it, so it
runs on the schedule you want to use for your personal backup
policy. Note in particular that most people will want to replace
my own scheme for daily backups. You'll likely either ignore dailies
(you wouldn't do that, would you? :-) or set the parameters to format
a new disk just like I have it doing for a weekly backup.
(Note: I've tagged some areas that are candidates for customization
with *** CUSTOMIZE *** - MRR.)
This software is completely public domain.
Author:
--
Glenn | ...!uunet!anagld!dahlgren!glenn (UUCP)
Holliday | glenn@dahlgren.sed.csc.com (fully domained)
Version 1: October 1 1994
Version 1.1: March 25 1995 Added check if a weekly backup is in
same month as a full backup
Since it's small, the complete software engineering document
set follows. I thought this might be interesting, it's the easiest
way to explain what backup policies are and how I approached them,
and it may answer questions of the form "why in the world is _that_
in the code?" Feel free to strip out this part if you wish:
Problem analysis:
Implement a set of rules to do incremental backups.
Recognize daily, weekly, and monthly backups as different cases.
Automatically run MRBackup and set up its parameters for each case.
Backup rules:
Keep a full backup set, a monthly backup set, a weekly
backup set, and six daily backup sets (one for each day between
weekly backups). Backup every day.
Assume that full backups (the entire disk) are done by hand
when needed. On the first day of a month, backup all files changed
since the date of the most recent full backup. On the first day of
a week (Sunday), backup all files changed since the date of the most
recent monthly backup. On any other day, backup all files whose
archive bits are clear (these are all files changed since the last
backup). On every backup, set the archive bits of all files backed
up.
Monthly and weekly backups are done to a set of diskettes.
Daily backups (assuming a small amount of change each day) are done to
subdirectories of a single diskette, named for each day.
This program assumes that you keep a record of the date
on which the most recent full backup was done. It does not provide
for making a full backup, or for storing that date. Some interesting
extensions could help out with that chore. I do full backups whenever
my set of monthly backup floppies overflows a box full, store the date
in a file in s:, and have my "backupifold" script supply that date
when it calls GHBackup.rexx.
Design to automate the backup rules:
Run mrbackup.rexx daily. In this program,
Get the current date, day of week,
date of last monthly backup, and
date of last full backup.
Classify current date as new month, new week, or ordinary day.
(This partitions the set of all dates into equivalence
classes, where each equivalence class is identified by
one of the values of a data type with three possible values.)
If the current date is:
new month,
new week,
ordinary day
Run MRBackup with the selected parameters.
Implementation:
GHBackup.rexx is run daily by some other mechanism. If you
leave your system on all the time, you probably want to put an entry
in your crontab to run it at the same time each day. I turn my
system off overnight, so I have cron run a program called "backupifold"
several times a day. It checks a timestamp of the last backup, and
runs GHBackup.rexx if the timestamp is more than a day old. I did not
include this program because it uses some shenaigans I don't like to
recogize elapsed time. If I ever get around to writing the more
elegant solution I have in mind, I'll give it away.
Input arguments:
If any of these are absent, GHBackup.rexx uses defaults. The
defaults are declared as ARexx variables at the beginning of the
code.
arg description default
homePath String, name of disk or other DH1:
filepath to the disk area to be
backed up
backupPath String, filepath to the backup DF0:
medium or directory
lastFullBackupDate String, date in AmigaDOS format Jan 1 1978
on which the last full backup
was done.
This program follows the design outline, using several
functions for modularity. The outline of the code is as follows:
date = date()
classifydate(date)
select
newmonth
setNewMonth()
newweek
setNewWeek()
daily
setNewDay()
end of program
classifydate(date)
parse date to get day, month, year, day of week
if day is 1, classify as newmonth
else if day of week is Sunday, classify as newweek
else classify as daily
return classification
setNewMonth():
(Back up everything since last full backup)
build "files since" date of last full backup,
select df0:, AmigaDos, quick format, ignore archive bits,
and no compression
setNewWeek():
(Back up everything since last monthly backup.
Assume date of last monthly backup is the first of the month)
build "files since" first day of current month,
select df0:, AmigaDos, quick format, ignore archive bits,
and no compression
setNewDay():
(Backup up everything since most recent backup.
Assume that's everything since archive bits were last set,
= everything with archive bits clear)
build backup path, AmigaDos, no format, test archive bits,
and 16 bit compression
*********************************************************************/
/********************
body of ARexx program
********************/
/*******************************************
During debugging, want to see all the errors
*******************************************/
/* TRACE INTERMEDIATE */
signal on ERROR
signal on BREAK_C
options results
/*** CUSTOMIZE ***/
defaultHomePath = "DH1:"
defaultBackupPath = "DF0:"
defaultLastFullBackup="01-Jan-78 00:00:00"
ARG homepath backuppath lastFullBackup
if homepath = '' then
homepath = defaultHomePath
if backuppath = '' then
backuppath = defaultBackupPath
if lastFullBackup = '' then
lastFullBackup = defaultLastFullBackup
/****************************************************************
Arexx parsing has the nasty habit of leaving the leading space on
the last of a string of arguments that it parses from a command
line. There are code-intensive ways of checking and cleaning up
all the arguments. Since I know it'll only be a problem on the
last one, here's a cheap way of cleaning it up.
****************************************************************/
lastFullBackup = strip(lastFullBackup)
/***************************************
Be sure MRBackup is running. Assume
only one copy needed, always address the
first MRBackup Rexx port.
startMacro(port, program) is a standard
Rexx macro that, if its first argument
is not already there, runs its second
argument and waits for its first
argument to appear.
***************************************/
toReturn = startServer('MRBackup_#1', 'mrbackup:mrbackup')
address 'MRBackup_#1'
takecontrol
poptofront
/***************************************
Get date, including weekday.
***************************************/
date = date('normal')
weekday = date('weekday')
/**********************************************
returns dateclass = newmonth, newweek, or daily
**********************************************/
dateclass = classifydate(date, weekday)
/***************************************
send ARexx commands to set MRBackup
parameters for the type of date
***************************************/
select
when dateclass = 'newmonth' then
toReturn = setNewMonth(homepath, backuppath, lastFullBackup)
when dateclass = 'newweek' then
toReturn = setNewWeek(homepath, backuppath, date, lastFullBackup)
when dateclass = 'daily' then
toReturn = setNewDaily(homepath, backuppath, weekday)
otherwise
do
Say 'unrecognized date type ' || dateclass
toReturn = 'FAIL'
error /* Use error: function to exit */
end
end
/***************
Start the backup
***************/
if toReturn = 'OK' then
do
backup
if rc ~= 0 then
do
say "Backup failed. Error code: " || rc
error /* Exit through error handler */
end
quit /* command to MRBackup to quit */
end
else
error
exit 0 /* end of program, success return code */
/*********************************************************************
classifydate(date, weekday)
Function to decide if a date is the first of month or week
*********************************************************************/
classifydate:
date = arg(1)
weekday = arg(2)
parse var date day month year garbageintail
select
when day = 1 then
datetype = 'newmonth'
when weekday = 'Sunday' then
datetype = 'newweek'
otherwise
datetype = 'daily'
end
return datetype
/*********************************************************************
setNewMonth(homepath, backuppath, lastFullBackup)
Inputs:
homepath String, filepath to be backed up
backuppath String, filepath to be backed up
lastFullBackup String, date in AmigaDOS format of
last full backup
Function to set MRBackup's parameter for monthly backup.
Back up everything since last full backup. Build "files since" date
of last full backup, select df0:, quick format, ignore archive bits,
and no compression.
*********************************************************************/
setNewMonth:
homepath = arg(1)
backuppath = arg(2)
lastBackup = arg(3)
/**********************************************************
The date to backup from is midnight of the date of the last
full backup.
**********************************************************/
parse var lastBackup weekday datestring timestring
/*** CUSTOMIZE ***/
testdate = datestring || " 00:00:00"
compression = 'None'
formatting = 'Quick'
testbits = 'No'
comment = "Monthly backup: All files since date of last full backup"
toReturn = setParameters(homepath, backuppath, comment, compression, ,
formatting, testdate, testbits)
return toReturn
/*********************************************************************
setNewWeek(homepath, backuppath, date, lastFullBackup)
Inputs:
homepath String, filepath to be backed up
backuppath String, filepath to be backed up
date String, current date in ARexx form
(day month year
as opposed to AmigaDOS form day-month-year)
lastFullBackup String, current date in AmigaDos form
(day-month-year)
Function to set MRBackup's parameter for weekly backup.
Back up everything since last monthly backup, = first day of the
month in the input date. If the last full backup happened during
this month, use that date instead of the first of the month.
Build "files since" date of the first of the month/last full backup,
select df0:, quick format, ignore archive bits, and no compression.
March 18 1995: Added check for last full backup since first of month
*********************************************************************/
setNewWeek:
homepath = arg(1)
backuppath = arg(2)
date = arg(3)
lastfullbackup = arg(4)
/*************************************************
Translate lastfullbackup from day-month-year to day month year
Get the month, check if lastfullbackup was in same month.
Set new date to first day or month or lastfullbackup.
Translate 19yy to yy, use midnight on the first.
*************************************************/
lastfullbackup = translate(lastfullbackup, " ", "-")
parse var date oldday month year rest
parse var lastfullbackup dayname fullday fullmonth fullyear rest
/*****************************************
Get months in all uppercase for comparison
*****************************************/
month = translate(month)
fullmonth = translate(fullmonth)
yearpart = right(year, 2)
fullyearpart = right(fullyear, 2)
if month = fullmonth & yearpart = fullyearpart then
do
testdate = fullday || '-' || fullmonth || '-' || fullyearpart || " 00:00:00"
/* testdate = lastfullbackup */
comment = "Weekly backup: All files since date of last full backup"
end
else
do
testdate = '01-' || month || '-' || yearpart || " 00:00:00"
comment = "Weekly backup: All files since first of this month"
end
/*** CUSTOMIZE ***/
compression = 'None'
formatting = 'Quick'
testbits = 'No'
toReturn = setParameters(homepath, backuppath, comment, compression, ,
formatting, testdate, testbits)
return toReturn
/*********************************************************************
setNewDaily(homepath, backuppath, weekday)
Inputs:
homepath String, filepath to be backed up
backuppath String, filepath to be backed up
weekday String, current day of the week
Function to set MRBackup's parameters for daily backup.
Back up everything that has archive bits clear, build a backup
filename from the current weekday, no format, and 16-bit compression.
*********************************************************************/
setNewDaily:
homepath = arg(1)
backupdev = arg(2)
weekday = arg(3)
/*** CUSTOMIZE ***/
backuppath = backupdev || weekday || "/"
testdate = 'nil'
compression = '16-Bit'
formatting = 'None'
testbits = 'Yes'
comment = "Daily backup: All files with archive bit clear"
toReturn = setParameters(homepath, backuppath, comment, compression, ,
formatting, testdate, testbits)
return toReturn
/*********************************************************************
setParameters(homepath, backuppath, comment, compression, formatting,
testdate, testbits)
Inputs:
homepath String, filepath to disk area to back up
backuppath String, filepath to disk to which the backup
is to be saved
comment String, to display in MRBackup's comment gadget.
Informs user what type of backup is being done.
compression String, None or 16-Bit.
testdate String, an AmigaDOS date or nil. nil indicates
the date is not tested.
testbits String, YES or NO. If archive bits are tested,
testdate is not used. If archive bits are not
tested, testdate is used.
Returns:
toReturn String, OK or FAIL (conforms to the code returned
by each MRBackup command). Tells the caller if
everything was set successfully.
This function sends ARexx commands to MRBackup to set the
parameters calculated by earlier functions. It tests for successful
completion of each ARexx message.
Assume that standard parameters common to all types
of backups (e.g. mode = AmigaDOS) are set in the usual
MRBackup.init, which MRBackup loaded on startup.
*********************************************************************/
setParameters:
arg homepath, backuppath, comment, compression, formatting, testdate, ,
testbits
/*************************************************
Check the backup disk is present before giving the
setbackpath command. If it's a device name,
MRBackup checks it when it's time to begin writing
to it. If it contains a directory path,
MRBackup requires that directory be available on
a mounted device when the setbackpath command
is issued.
*************************************************/
if right(backuppath, 1) ~= ':' then
do while ~exists(backuppath)
string = "'Please mount " || backuppath || " in any drive'"
'getchoice' '"'string'"' 'OK'
end
setfilemode "Replace"
/***************************
This section sets all the
MRBackup parameters. The
strategy is:
set a parameter
as long as no error yet,
keep going to set more
Most of the ARexx commands
put a return code, OK or
FAIL, in the variable
result. Test result after
each command, and keep going
as long as it's OK.
Some of the commands put
something else in result.
For these, check the ARexx
return variable rc. Set
result to indicate the same
state that rc indicates.
This keeps the current
state consistent in result,
and lets it be used
consistently to test if
the next parameter should
be tested.
If any command returns
a failure code, all of
the remaining tests
fall through, and no
more commands are sent to
MRBackup.
***************************/
if result ~= 'FAIL' then
setbackpath backuppath /* returns result = OK or FAIL */
if result ~= 'FAIL' then
sethomepath homepath /* returns result = current path, check rc */
if rc ~= 0 then
do
result = 'FAIL'
end
else
listing 'YES' /* returns result = OK or FAIL */
if result ~= 'FAIL' then
setarcbits 'yes' /* always set the bits after we finish backing up */
if result ~= 'FAIL' then
'setinfogadget' '"'comment'"' /* always returns result = OK */
if result = 'OK' then
'setcompression' '"'compression'"' /* returns result = OK or FAIL */
if result ~= 'FAIL' then
'setformatting' '"'formatting'"' /* returns current mode, check rc */
if rc ~= 0 then
do
result = 'FAIL'
end
else
'testarcbits' '"'testbits'"' /* Set "test bits" to either Yes or No */
if result ~= 'FAIL' then
do
/***********************************************
only test date if we aren't testing archive bits
***********************************************/
if testbits = 'NO' then
do
'dateformat 0'
settestdate '"'testdate'"' /* returns current date, check rc */
if rc ~= 0 then result = 'FAIL'
else result = 'OK'
end
end
return result
/*********************************************************************
error
This function handles an error condition. It exits with
return code 6, which is 1 higher than a warning. It sends a
quit to MRBackup.
*********************************************************************/
error:
say "Exiting because of error"
quit /* command to MRBackup to quit */
exit 6
/*********************************************************************
break_c
This function exits the ARexx script on a user control-c
interrupt. It does not stop MRBackup. It exits with return code
5, which is a warning.
*********************************************************************/
break_c:
say "*** Control-C recieved. Stopped by user. ***"
/* Note: Do not command to MRBackup to quit. Leave running, assume
user needs to look at something.
*/
exit 5